﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace ProjectRoughWork
{
    class Squad : ProjectAIState
    {
        public enum SquadState { Attacking, SeekingCover, Moving };

        /// <summary>
        /// 1-Parameter Constructor that initializes the squad with the given array of squad actors
        /// </summary>
        /// <param name="initSquad">Array of SquadActors that'll compose the squad</param>

        public Squad(SquadActor[] initSquad, GameplayScreen screen, bool initPlayerSquad) : base(screen)
        {
            //Initialize the squad acotrs

            squad = new SquadActor[3];

            squad[0] = initSquad[0];
            squad[1] = initSquad[1];
            squad[2] = initSquad[2];

            playerSquad = initPlayerSquad;

            //Switch to attacking state

            ChangeState(SquadState.Attacking, true);

            cohesion = new Cohesion(squad);
            allignment = new Allignment(squad);
            separation = new Separation(squad);
        }

        /// <summary>
        /// Property for the squad's state
        /// </summary>

        public SquadState State
        {
            get { return state; }
        }

        /// <summary>
        /// Property for the squad actors
        /// </summary>

        public SquadActor[] SquadUnits
        {
            get { return squad; }
        }

        /// <summary>
        /// Method for handling Squad State changes
        /// </summary>
        /// <param name="newState"></param>
        /// <param name="init"></param>

        public void ChangeState(SquadState newState, bool init)
        {
            if (!init)
            {
                //If not called from default constructor
                //      invalidate all cover in order to re-establish the status of the cover points

                gameScreen.InvalidateCover();
            }

            for (int index = 0; index < 3; index++)
            {
                if (!squad[index].isDead())
                {
                    //If actor is not dead
                    //      Change their current AI State based on the new Squad State

                    if (newState == SquadState.Attacking)
                    {
                        squad[index].CurrentAIState = new Attack(squad[index], gameScreen, playerSquad);
                        squad[index].CurrentUnitState = SquadActor.UnitState.Attacking;
                    }
                    else if (newState == SquadState.SeekingCover)
                    {
                        Queue<Node> path = gameScreen.PathFindToCover(squad[index].getPosition(), Vector3.Zero, 0f);

                        if (path != null)
                        {
                            squad[index].CurrentAIState = new PathFollowing(squad[index], path);
                        }
                        else
                        {
                            squad[index].CurrentAIState = new Attack(squad[index], gameScreen, playerSquad);
                        }
                    }
                }
            }
            state = newState;
        }

        /// <summary>
        /// Tests if the squad is in good health by testing if the squad's total current health is below half the total of the maximum
        /// </summary>
        /// <returns>True if above half of total max health, False if not</returns>

        public bool CheckSquadHealth()
        {
            float averageCurrentHealth = squad[0].CurrentHealth + squad[1].CurrentHealth + squad[2].CurrentHealth;
            averageCurrentHealth /= 3;

            float averageMaxHealth = squad[0].MaxHealth + squad[1].MaxHealth + squad[2].MaxHealth;
            averageMaxHealth /= 3; 

            if (averageCurrentHealth < averageMaxHealth / 2)
            {
                return false;
            }

            return true;
        }

        public override void VOnUpdate()
        {
            int userIndex;

            //Gather Strategic information
            /*
             *  Info to calculate:
             *  1. Distance from enemy Squad
             *  2. Current Squad Health Status
             *  
            */

            //1. Distance from enemy squad

            Rectangle enemyInfluenceBox = gameScreen.CalculateOpposingSquadInfluence(playerSquad);

            //2.Current Squad Health Status

            bool squadInGoodHealth = CheckSquadHealth();


            //3.Determine player index 

            userIndex = 0;

            //Decision Making

            /*
             * Conditions for state changing:
             * 1. Attacking - Attack when health is optimal
             * 2. SeekCover - After Moving? 
             * 3. Move - If 
             */

            if ( (squadInGoodHealth) && (state != SquadState.Attacking))
            {
                //ChangeState(SquadState.Attacking, false);
            }
            else if (!squadInGoodHealth)
            {
                //ChangeState(SquadState.SeekingCover, false);
            }


            if (playerSquad)
            {
                for (int index = 0; index < 3; index++)
                {
                    if ( (squad[index].CurrentUnitState == SquadActor.UnitState.Attacking) && 
                        (Math.Abs((squad[userIndex].getPosition() - squad[index].getPosition()).Length()) > 300) 
                        )
                    {
                        Queue<Node> path = gameScreen.PathFindToTarget(squad[index].getPosition(), squad[userIndex].getPosition(), 100);
                        squad[index].CurrentAIState = new PathFollowing(squad[index], path);
                        squad[index].CurrentUnitState = SquadActor.UnitState.Regrouping;
                        squad[index].Moving = true;
                    }
                    else if ((squad[index].CurrentUnitState == SquadActor.UnitState.Regrouping) && (((PathFollowing)squad[index].CurrentAIState).ReachedEnd))
                    {
                        squad[index].CurrentAIState = new Attack(squad[index], gameScreen, playerSquad);
                        squad[index].CurrentUnitState = SquadActor.UnitState.Attacking;
                        squad[index].Moving = false;
                    }

                }
            }

            //Individual Squad AI Execution

            for (int index = 0; index < 3; index++)
            {
                if ((!squad[index].isDead()) && (!squad[index].User))
                {
                    squad[index].CurrentAIState.VOnUpdate();
                }
            }

            //Squad AI Adjustments

            if (state == SquadState.Moving)
            {
                cohesion.VOnUpdate();
                allignment.VOnUpdate();
            }
            separation.VOnUpdate();

            for (int index = 0; index < 3; index++)
            {
                if ( (!squad[index].isDead()) && (!squad[index].User) )
                {
                    gameScreen.WallObstacleAvoidance(squad[index]);
                    EventMoveActor moveEvent = new EventMoveActor(squad[index].getID(), squad[index].getPosition() + squad[index].getVelocity());
                    EventManager.GetInstance().VQueueEvent(moveEvent);
                }
            }

            base.VOnUpdate();
        }

        //Data Members
        SquadActor[] squad;
        SquadState state;

        Cohesion cohesion;
        Allignment allignment;
        Separation separation;

        bool playerSquad;
    }
}
